package com.cyzy.service.impl;

import com.cyzy.service.DistributedLockService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

/**
 * 基于Redis的简化分布式锁实现（备用方案）
 * 如果Redisson有问题时使用
 */
@Slf4j
// @Service  // 先注释掉，优先使用Redisson版本
public class SimpleDistributedLockServiceImpl implements DistributedLockService {
    
    @Autowired
    private StringRedisTemplate redisTemplate;
    
    private static final String UNLOCK_SCRIPT = 
        "if redis.call('get', KEYS[1]) == ARGV[1] then " +
        "return redis.call('del', KEYS[1]) " +
        "else return 0 end";
    
    @Override
    public <T> T executeWithLock(String lockKey, long waitTime, long leaseTime, TimeUnit timeUnit, Supplier<T> supplier) {
        String lockValue = UUID.randomUUID().toString();
        long waitTimeMillis = timeUnit.toMillis(waitTime);
        long leaseTimeSeconds = timeUnit.toSeconds(leaseTime);
        
        long startTime = System.currentTimeMillis();
        
        try {
            // 尝试获取锁
            while (System.currentTimeMillis() - startTime < waitTimeMillis) {
                Boolean acquired = redisTemplate.opsForValue()
                    .setIfAbsent(lockKey, lockValue, leaseTimeSeconds, TimeUnit.SECONDS);
                
                if (Boolean.TRUE.equals(acquired)) {
                    log.info("成功获取分布式锁, lockKey: {}", lockKey);
                    try {
                        return supplier.get();
                    } finally {
                        // 释放锁
                        DefaultRedisScript<Long> script = new DefaultRedisScript<>(UNLOCK_SCRIPT, Long.class);
                        Long result = redisTemplate.execute(script, Collections.singletonList(lockKey), lockValue);
                        if (result != null && result == 1) {
                            log.info("释放分布式锁, lockKey: {}", lockKey);
                        }
                    }
                }
                
                // 等待50ms后重试
                Thread.sleep(50);
            }
            
            log.warn("获取分布式锁失败, lockKey: {}", lockKey);
            throw new RuntimeException("系统繁忙，请稍后重试");
            
        } catch (InterruptedException e) {
            log.error("获取分布式锁被中断, lockKey: {}", lockKey, e);
            Thread.currentThread().interrupt();
            throw new RuntimeException("系统繁忙，请稍后重试");
        }
    }
    
    @Override
    public <T> T executeWithLock(String lockKey, Supplier<T> supplier) {
        return executeWithLock(lockKey, 3, 10, TimeUnit.SECONDS, supplier);
    }
} 